//=---------------------------------------------------------------------=
//
// $Id: AxTypes.cpp,v 1.14 2008/08/18 11:27:03 stuart_hc Exp $ $Name: V113 $
//
// The contents of this file are subject to the AAF SDK Public
// Source License Agreement (the "License"); You may not use this file
// except in compliance with the License.  The License is available in
// AAFSDKPSL.TXT, or you may obtain a copy of the License from the AAF
// Association or its successor.
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
// the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code of this file is Copyright 1998-2004, Licensor of the
// AAF Association.
//
//=---------------------------------------------------------------------=

#if defined(OS_WINDOWS)
#pragma warning(disable:4786)
// The prama is busted. It must be above std lib header includes, even then
// it doesn't work. See:
// http://support.microsoft.com/support/kb/articles/Q167/3/55.ASP
// http://support.microsoft.com/support/kb/articles/Q195/3/86.ASP
// http://support.microsoft.com/support/kb/articles/Q122/5/39.ASP
#endif

#include "AxTypes.h"
#include "AxUtil.h"
#include "AxEx.h"

#include <iostream>
#include <map>


#include <cstring>
#include <stdio.h>
#include <assert.h>

namespace {

// Here is the official AAF Example programs (a.k.a "Ax") product UUID
// as generated by Microsoft's UUIDGEN.EXE program:
// 684074c2-02da-41db-b6fc-995b46234b19
  
aafUID_t axUuid = { 0x684074c2, 0x02da, 0x41db,
		    { 0xb6, 0xfc, 0x99, 0x5b, 0x46, 0x23, 0x4b, 0x19 } };

// FIXME: Should the version match the spec version, or the sdk release 
//  version, or what?
aafProductVersion_t axProductVersion = { 3, 5, 7, 11, kAAFVersionPrivateBuild };

}

AxProductIdentification::AxProductIdentification()
  : _companyName( L"AAF Association Inc." ),
    _productName( L"AAF SDK Examples" ),
    _productVersionString( L"3.141592654" ),
    _platform( L"All Platform" ),
    _productVersion( axProductVersion )

{
  init( axUuid );
}


AxProductIdentification::AxProductIdentification(
  const AxString& companyName,
  const AxString& productName,
  const AxString& productVersionString,
  const AxString& platform,
  const aafUID_t& productId,
  const aafProductVersion_t& productVersion
  )
  : _companyName( companyName ),
    _productName( productName ),
    _productVersionString( productVersionString ),
    _platform( platform ),
    _productVersion( productVersion )
{
  init( productId );
}

void AxProductIdentification::init( const aafUID_t& productId )
{
   // All _productId strings get pointers to memory owned
   // (transitively) by this object.
  _productId.companyName          = const_cast<aafCharacter*>( _companyName.c_str() );
  _productId.productName          = const_cast<aafCharacter*>( _productName.c_str() );
  _productId.productVersionString = const_cast<aafCharacter*>( _productVersionString.c_str() );
  _productId.platform             = const_cast<aafCharacter*>( _platform.c_str() );

  // _productId.productVersion get a pointer to memory owned by this
  // object as well.
  _productId.productVersion       = &_productVersion;

  // productId is copied into _productId.productID because
  // aafProductIdentification_t stores this by value - unlike the
  // others which are all pointers.
  _productId.productID            = productId;
}

AxProductIdentification::~AxProductIdentification()
{}

const aafProductIdentification_t* AxProductIdentification::getProductId() const
{
  return &_productId;
}

std::wostream& AxProductIdentification::dump( std::wostream& os ) const
{
	using namespace std; 

	os << L"Product Identification:   " << endl;
	os << L"\tCompany Name:           " << _companyName          << endl;
	os << L"\tProduct Name:           " << _productName          << endl;
	os << L"\tProduct Version String: " << _productVersionString << endl;
    os << L"\tProduct UUID:           " << _productId.productID  << endl;
	os << L"\tPlatform:               " << _platform             << endl;
	os << L"\tProduct Version:        " << _productVersion       << endl;
 
	return os;
}

std::wostream& operator<<( std::wostream& os, const AxProductIdentification& id )
{
	return id.dump( os );
}

std::wostream& operator<<( std::wostream& os, const aafUID_t& uid )
{
    const int bufSize = 37;
	char buf[bufSize];
	int rc;
	using namespace std;

	// swprintf does not have uniform all platform support.
	// Instead, use sprintf and convert to wide characters.

	rc = sprintf( buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
				     uid.Data1, uid.Data2, uid.Data3,
				     uid.Data4[0], uid.Data4[1],uid.Data4[2], uid.Data4[3],
				     uid.Data4[4], uid.Data4[5],uid.Data4[6], uid.Data4[7] );
	if ( -1 == rc ) {
	  throw AxEx( L"sprintf failed" );
	}

	AxString wBuf = AxStringUtil::mbtowc( buf );

	os << wBuf;

	return os;
}

std::wostream& operator<<( std::wostream& os, const aafProductVersion_t& pv )
{
	using namespace std;

	os << pv.major << L" " << pv.minor << L" " << pv.tertiary << L" " << pv.patchLevel << L" ";
	
	// FIXME - should be in a central name repository.

	map<int,AxString> releaseTypeNames;

	releaseTypeNames[ kAAFVersionUnknown]		= L"AAFVersionUnknown";
	releaseTypeNames[ kAAFVersionReleased ]		= L"AAFVersionReleased";
	releaseTypeNames[ kAAFVersionDebug]			= L"AAFVersionDebug";
	releaseTypeNames[ kAAFVersionPatched]		= L"AAFVersionPatched";
	releaseTypeNames[ kAAFVersionBeta]			= L"AAFVersionBeta";
	releaseTypeNames[ kAAFVersionPrivateBuild ] = L"AAFVersionPrivateBuild";

	assert( releaseTypeNames.find( pv.type ) != releaseTypeNames.end() );
	
	os << releaseTypeNames[ pv.type ];

	return os;
}

bool operator<( const aafUID_t& uidL, const aafUID_t& uidR )
{
	return 0 > ::memcmp( &uidL, &uidR, sizeof( aafUID_t ) );
}

#if !defined(DISABLE_DYNAMIC_LOADING)
// These two operators are also defined in ImplAAFCloneResolver.cpp
// so only build if this is not a static build to avoid a clash.
bool operator==( const aafUID_t& uidL, const aafUID_t& uidR )
{
	return 0 == ::memcmp( &uidL, &uidR, sizeof( aafUID_t ) );
}

bool operator==( const aafMobID_t& lhs, const aafMobID_t& rhs )
{
  return 0 == ::memcmp( &lhs, &rhs, sizeof( aafMobID_t ) );
}
#endif

#if !defined(OS_WINDOWS)
bool operator==( const tagGUID& uidL, const tagGUID& uidR )
{
	return 0 == ::memcmp( &uidL, &uidR, sizeof( tagGUID ) );
}
#endif

bool operator<( const aafMobID_t& lhs, const aafMobID_t& rhs )
{
  return 0 > ::memcmp( &lhs, &rhs, sizeof( aafMobID_t ) );
}
